# coding:utf-8
'''
Created on 2017/09/19
@author:yxf
'''
from werkzeug.wrappers import Request, Response
from werkzeug.serving import run_simple
from jsonrpc import JSONRPCResponseManager, dispatcher
import json
import os
#import matplotlib.image as mpimg
from PIL import Image
import time
import base64
import requests
import pymysql

mean = 23.869413461

from Insert_data import Insert_data
import face_recognition

from face_extraction import Generate_FE_Json

import logging

import scipy.stats
import numpy as np
import hashlib
from datetime import datetime
test = datetime.now()
test = test.strftime('%hh/%mm/%ss/%m/%d/%Y')
test = test + "gamma_lab"

# 连接数据库
def Connection():
    connection = pymysql.connect(host='localhost',
                                 user='yaoxufeng',
                                 password='yaoxufeng004',
                                 db='gamma_lab',
                                 charset='utf8mb4',
                                 cursorclass=pymysql.cursors.DictCursor)
    return connection

# select数据库值
def Select(select_sql):
    try:
        connection = Connection()
        with connection.cursor() as cursor:
            sql = "{}".format(select_sql)
            cursor.execute(sql)
            result = cursor.fetchall()
    except Exception as e:
        #connection.close()
        pass
        logging.info(e)
    return result

# 人脸识别
def Recognition(select_sql, unknown_encoding):
    result_attr = {}
    try:
        result = Select(select_sql)

        result_data = [i["face_encoding"].split(",") for i in result]
        result_data = [[float(j) for j in i] for i in result_data]
        results = face_recognition.compare_faces(result_data, unknown_encoding)
    except Exception as e:
        logging.info(e)
    if True in results:
        index = results.index(True)
        result_attr = result[index]
        result_attr.pop("id", None)
    else:
        result_attr["flag"] = "0"
    result_attr = json.dumps(result_attr)
    return result_attr

#unknown_image = face_recognition.load_image_file("data/photos/yaoxufeng.jpeg")
#unknown_encoding = face_recognition.face_encodings(unknown_image)[0]

#select_sql = "select * from t_gamma_mirror where flag='1';"
#result = Recognition(select_sql, unknown_encoding)
#print (result)


# 计算md5值，用于本地存储
def computeMD5hash(string):
    m = hashlib.md5()
    m.update(string.encode('utf-8'))
    return m.hexdigest()

filename=computeMD5hash(test)

# 保存图片
def SaveImage(base64string, filename):
    with open("data/{}".format(filename), "wb")as image_file:
        image_file.write(base64.decodestring(base64string.encode()))

# 微软接口
def Micro_Face_api(filepath):
    subscription_key = 'c959e609e551407898a8de96c1745018'
    uri_base = 'https://westcentralus.api.cognitive.microsoft.com'
    headers = {'Content-Type': 'application/octet-stream',
                'Ocp-Apim-Subscription-Key': subscription_key
              }
    params = {'returnFaceId': 'false',
              'returnFaceLandmarks': 'false',
              'returnFaceAttributes': 'age,gender'
             }
    with open(filepath, "rb") as imageFile:
          body = imageFile.read()
    response = requests.request('POST', uri_base + '/face/v1.0/detect', data=body, headers=headers, params=params, timeout=4)
    res = json.loads(response.text)
    return res

# face++接口
@dispatcher.add_method
def Face_pluss(base64string, filename=filename):
    #data = []
    detect_url = "https://api-cn.faceplusplus.com/facepp/v3/detect"
    key = "2U-4xDmbcbfcZtN6vjrKIi9TAUrBaqDu"
    secret = "a_thItlylpTBAsoqRwPfrEoxlh6cFRMg"
    parameter = {'api_key':key, 'api_secret':secret}
    parameter['image_base64'] = base64string
    parameter['return_attributes'] = "gender,emotion,age"
    boundary = '----------%s' % hex(int(time.time() * 1000))
    headers = {'Content-Type', 'multipart/form-data; boundary=%s' % boundary, 'Referer','http://remotserver.com/'}
    r = requests.post(detect_url, data=parameter, headers=headers).text
    res = json.loads(r)
    #print (res)
    #response = json.loads(res["result"])
    response1 = res["faces"][0]["attributes"]
    age = response1["age"]["value"]
    gender = response1["gender"]["value"]

    return age, gender

# 本地age_gender模型
@dispatcher.add_method
def Age_Gender_Model(base64string, filename=filename):
    data = []
    SaveImage(base64string, filename)
    if os.path.isfile("data/{}".format(filename)):
        im = Image.open("data/{}".format(filename))
        im = im.resize((64, 64), Image.ANTIALIAS)
        data.append(np.array(im))
        data = np.array(data, dtype=np.uint8)
        data = Age_Gender(data)
        return data
    else:
        time.sleep(1)

# 本地face_bmi模型
@dispatcher.add_method
def Facebmi_Model(base64string, filename=filename):
    data = []
    SaveImage(base64string, filename)
    if os.path.isfile("data/{}".format(filename)):
        im = Image.open("data/{}".format(filename))
        im = im.resize((96, 118), Image.ANTIALIAS)
        data.append(np.array(im))
        data = np.array(data, dtype=np.uint8)
        data = Facebmi(data)
        return data
    else:
        time.sleep(1)

# 本地颜值模型
@dispatcher.add_method
def Beauty_Model(base64string, filename=filename):
    data = []
    SaveImage(base64string, filename)
    if os.path.isfile("data/{}".format(filename)):
        im = Image.open("data/{}".format(filename))
        im = im.resize((178, 218), Image.ANTIALIAS)
        data.append(np.array(im))
        data = np.array(data, dtype=np.uint8)
        data = Smile_Beauty(data)
        return data
    else:
        time.sleep(1)

# 本地眼袋模型
@dispatcher.add_method
def Bag_under_eye_Model(base64string, filename=filename):
    data = []
    SaveImage(base64string, filename)
    if os.path.isfile("data/{}".format(filename)):
        #data64array = mpimg.imread("data/{}".format(filename))
        #data.append(np.resize(data64array, (218, 178, 3)))
        im = Image.open("data/{}".format(filename))
        im = im.resize((178, 218), Image.ANTIALIAS)
        data.append(np.array(im))
        data = np.array(data, dtype=np.uint8)
        data = Bag_under_eye(data)
        return data
    else:
        time.sleep(1)

# 旧版的调用facemodel
@dispatcher.add_method
def Face_Model(base64string, filename=filename):
    age, gender = "abc", "dfg"
    data1, data2, data3, data = [], [], [], {}
    SaveImage(base64string, filename)
    if os.path.isfile("data/{}".format(filename)):
        #unknown_image = face_recognition.load_image_file("data/{}".format(filename))
        #unknown_encoding = face_recognition.face_encodings(unknown_image)[0]
        #sql = "select * from t_face where flag = '1';"
        #result_attr = Recognition(sql, unknown_encoding)
        #result_attr = json.loads(result_attr)
        #print (result_attr)
        if 1 == 2:
            pass
        #if result_attr["flag"] == "1":
        #    result_attr.pop("flag", None)
        #    data =  json.dumps(result_attr)
        else:
            im = Image.open("data/{}".format(filename))
            img1 = im.resize((64, 64), Image.ANTIALIAS)
            img2 = im.resize((96, 118), Image.ANTIALIAS)
            img3 = im.resize((178, 218), Image.ANTIALIAS)
            data1.append(np.array(img1))
            data2.append(np.array(img2))
            data3.append(np.array(img3))
            data1 = np.array(data1, dtype=np.uint8)
            data2 = np.array(data2, dtype=np.uint8)
            data3 = np.array(data3, dtype=np.uint8)
            result1 = model_age.predict(data1)
            age_gender = 1
            try:
            #age, gender = Face_pluss(base64string, filename=filename)
                1 == 2
            except Exception as e:
                pass
            if age == "abc":
                age_gender = 2
            result2 = model_facebmi.predict(data2 / 255.)
            result3 = model_beauty.predict(data3 / 255.)
            result4 = model_bag_under_eye.predict(data3 / 255.)
            for i in range(data1.shape[0]):
                bmi, mood, fatigue = float(result2[i][0] * 16 + mean), float(result3[1][i][0]), float(result4[3][i][0])
                #fatigue = scipy.stats.norm(0.519356185, 0.201668739).cdf(fatigue)
                fatigue = round(fatigue * 100)
            #mood = scipy.stats.norm(0.051470661, 0.089599092).cdf(mood)
            #mood = round(mood * 100)
                if mood > 0.05:
                    mood = round(70 + mood * 30)
                elif mood > 0.01:
                    mood = round(60 + mood * 250)
                else:
                    mood = round(50 + mood * 1000)
                if bmi > 24:
                    bmi = round(70 - ((bmi - 24) * 8))
                elif bmi > 20:
                    bmi = round(100 - (abs(21.5 - bmi) * 20))
                else:
                    bmi = round(80 - ((24 - bmi) * 15))
            #if fatigue > 0.7:
            #    fatigue = round(80 - fatigue * 30)
            #elif fatigue > 0.4:
            #    fatigue = round(90 - fatigue * 50)
            #else:
            #    fatigue = round(100 -fatigue * 40)
                if age_gender == 2:
                    age = round(float(np.argmax(result1[1][i])))
                    data[i] = (str(result1[0][i][1]), str(age), str(bmi), str(mood), str(fatigue))
                elif age_gender == 1:
                    if str(gender) == "Male":
                        gender = "0.9"
                    else:
                        gender = "0.1"
                    age = round(float(age))
                    data[i] = (str(gender), str(age), str(bmi), str(mood), str(fatigue))
            data = json.dumps(data)
        return data
    else:
        time.sleep(1)

# 测试
@dispatcher.add_method
def Face_Extraction_test(base64string, face_landmark, filename=filename):
    data1, data = [], {}
    GFE = Generate_FE_Json()
    face_extraction = GFE.Compute_FE_Json(face_landmark)
    face_extraction = json.loads(face_extraction)
    SaveImage(base64string, filename)
    if os.path.isfile("data/{}".format(filename)):
        im = Image.open("data/{}".format(filename))
        img1 = im.resize((64, 64), Image.ANTIALIAS)
        data1.append(np.array(img1))
        data1 = np.array(data1, dtype=np.uint8)
        result_age = model_age.predict(data1)
    #for i in range(data1.shape[0]):
    data[0] = (str(result_age[0][0][1]), str(np.argmax(result_age[1][0])), str(face_extraction["eye_area_pos"]), str(face_extraction["nose_length_pos"]), str(face_extraction["mouth_area_pos"]))
    data = json.dumps(data)
    return data


# 主要方法
@dispatcher.add_method
def Face_Extraction(base64string, face_landmark, filename=filename):
    #age = "22"
    gender = "2"
    data1, data = [], {}
    # 初始化data值，防止调用过程中出现问题返回null值
    data[0] = ("0", "1", "30", "0.6", "0.5", "0.4", "hi")
    # 日志 
    logging.info("{} is doing face_extraction".format(filename))
    print("{} is doing face_extraction in {}".format(filename, time.ctime()))
    # 提取人脸脸部特征
    GFE = Generate_FE_Json()
    face_extraction = GFE.Compute_FE_Json(face_landmark)
    face_extraction = json.loads(face_extraction)
    logging.info("{} is saving image".format(filename))
    # 保存图片
    SaveImage(base64string, filename)

    # 如果存在图片，进行下一步操作
    if os.path.isfile("data/{}".format(filename)):
        logging.info("{} is loading image".format(filename))
        print ("{} is loading image in {}".format(filename, time.ctime()))
        # 对图片进行face-encoding 操作
        unknown_image = face_recognition.load_image_file("data/{}".format(filename))
        logging.info("{} is doing face_encoding".format(filename))
        print ("{} is doing face_encoding in {}".format(filename, time.ctime()))
        unknown_encoding = face_recognition.face_encodings(unknown_image)
        #logging.info("unknown_encoding is {}".format(unknown_encoding))
        try:
            logging.info("{} encoding right?".format(filename))
            #logging.info(unknown_encoding[0])
            print ("{} encoding right? in {}".format(filename, time.ctime()))
            # 如果图片编码正确，进行下一步，否则跳出
            if unknown_encoding[0].size == 128:
                unknown_encoding = unknown_encoding[0]
                logging.info(unknown_encoding)
                logging.info("selecting..")
                sql = "select * from t_gamma_mirror where flag= '1';"
                logging.info("recognition..")
                result_attr = Recognition(sql, unknown_encoding)
                result_attr = json.loads(result_attr)
                logging.info(result_attr)
                logging.info("recognition done")
                # flag 返回1，2证明数据存在于数据库中，进行赋值
                if result_attr['flag'] in ["1", "2", 1, 2]:
                    result_attr.pop("face_encoding", None)
                    data[0] = (result_attr["flag"], result_attr["gender"], result_attr["age"], result_attr["eye_area"], result_attr["nose_length"], result_attr["mouth_area"], result_attr["face_name"])

                else:
                    # 调用微软接口
                    try:
                        logging.info("{} is calling microsoft_face_api".format(filename))
                        print ("{} is calling microsoft_face_api in {}".format(filename, time.ctime()))
                        filepath = "data/{}".format(filename)
                        res = Micro_Face_api(filepath)
                        age = res[0]["faceAttributes"]["age"]
                        gender = res[0]["faceAttributes"]["gender"]
                        if gender == "male":
                            gender = "1"
                        else:
                            gender = "0"
                    except Exception as e:
                        pass
                    # 如果接口调用正常，则通过，不正常，则调用本地模型
                    if gender != "2":
                        pass
                    else:
                        logging.info("{} calling local_age_model".format(filename))
                        print ("{} calling local_age_model in {}".format(filename, time.ctime()))
                        im = Image.open("data/{}".format(filename))
                        img1 = im.resize((64, 64), Image.ANTIALIAS)
                        data1.append(np.array(img1))
                        data1 = np.array(data1, dtype=np.uint8)
                        result_age = model_age.predict(data1)
                        gender = str(result_age[0][0][1])
                        age = str(np.argmax(result_age[1][0]))
                    eye_area = scipy.stats.norm(0.0403646039551264, 0.01676479201251127).cdf(face_extraction["eye_area_pos"])
                    nose_length = scipy.stats.norm(0.787294866235091, 0.08354285889870456).cdf(face_extraction["nose_length_pos"])
                    mouth_area = scipy.stats.norm(0.196757978606616, 0.07156009887478258).cdf(face_extraction["mouth_area_pos"])
                    data[0] = (str(0), str(gender), str(age), str(eye_area), str(nose_length), str(mouth_area), None)
                    unknown_encoding = ",".join(str(i) for i in unknown_encoding)
                    logging.info(unknown_encoding)
                    logging.info("{} is inserting".format(filename))
                    print ("{} is insering in {}".format(filename, time.ctime()))
                    insert_sql = "insert into t_gamma_mirror (`flag`, `face_encoding`, `gender`, `age`, `eye_area`, `nose_length`, `mouth_area`, `face_name`) values ('2', '{}', '{}', '{}', '{}', '{}', '{}', '{}')".format(unknown_encoding, gender, age, str(eye_area), str(nose_length), str(mouth_area), None)
                    #插入数据
                    #Insert_data(insert_sql)
        except Exception as e:
            logging.info(e)
    data = json.dumps(data)
    logging.info("{} done".format(filename))
    return data





@Request.application
def json_rpc(request):
    '''
    主要调用json_rpc的函数
    '''
    response = JSONRPCResponseManager.handle(request.data, dispatcher)
    return Response(response.json, mimetype='application/json')


if __name__ == "__main__":
    from Model import Age_Gender, Facebmi, Smile_Beauty, Bag_under_eye

    from Model import model_age, model_facebmi, model_beauty, model_bag_under_eye
    logging.getLogger('').handlers = []
    logging.basicConfig(level=logging.INFO,
                        format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                        datefmt='%Y-%m-%d,%H:%M:%S:%f',
                        filename='myapp.log',
                        filemode='w')
    run_simple("0.0.0.0", 8880, json_rpc)
